// File:    node.h
// Author:  Brian Vanderburg II
// Purpose: Expression node
//------------------------------------------------------------------------------


#ifndef __EXPREVAL_NODE_H
#define __EXPREVAL_NODE_H

// Includes
#include <vector>
#include <sstream>

#include "parser.h"

// Part of expreval namespace
namespace ExprEval
{
// Forward declarations
class ErrorInfo;
class Expression;
class FunctionFactory;


// Node class
//--------------------------------------------------------------------------
class Node
{
public:

    explicit
    Node (
        Expression *expr);

    virtual
    ~Node();

public:

    virtual double
    DoEvaluate (
        ErrorInfo& errors) const = 0;

    virtual std::pair<double, double>
    DoEvaluate (
        const std::string& var_symbol,
        ErrorInfo& errors) const = 0;

    virtual std::pair<double, double>
    DoEvaluate (
        const std::string& var_symbol_1,
        const std::string& var_symbol_2,
        ErrorInfo& errors) const = 0;

    virtual void
    Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool& good_parse) = 0;

    double
    Evaluate (
        ErrorInfo& errors) const; // Calls Expression::TestAbort, then DoEvaluate

    std::pair<double, double>
    Evaluate (
        const std::string& var_symbol,
        ErrorInfo& errors) const;

    std::pair<double, double>
    Evaluate (
        const std::string& var_symbol_1,
        const std::string& var_symbol_2,
        ErrorInfo& errors) const;

    virtual std::string
    get_renamed_expression (
        const std::string& var_map_name) const = 0;

protected:

    Expression *m_expr;
};

// General function node class
//--------------------------------------------------------------------------
class FunctionNode : public Node
{
public:
    FunctionNode (Expression *expr);
    ~FunctionNode();

    // Parse nodes and references
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    virtual std::string
    get_renamed_expression (
        const std::string& var_map_name) const = 0;

private:
    // Function factory
    FunctionFactory *m_factory;

    // Argument count
    long m_argMin;
    long m_argMax;
    long m_refMin;
    long m_refMax;

protected:
    // Set argument count (called in derived constructors)
    void SetArgumentCount (long argMin = 0, long argMax = 0,
                           long refMin = 0, long refMax = 0);

    // Function name (using factory)
    std::string GetName() const;

    // Normal, reference, and data parameters
    ::std::vector<Node*> m_nodes;
    ::std::vector<double*> m_refs;

    friend class FunctionFactory;
};

// Mulit-expression node
//--------------------------------------------------------------------------
class MultiNode : public Node
{
public:
    MultiNode (Expression *expr);
    ~MultiNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    ::std::vector<Node*> m_nodes;
};

// Assign node
//--------------------------------------------------------------------------
class AssignNode : public Node
{
public:
    AssignNode (Expression *expr);
    ~AssignNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    double *m_var;
    Node *m_rhs;
};

// Add node
//--------------------------------------------------------------------------
class AddNode : public Node
{
public:
    AddNode (Expression *expr);
    ~AddNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// Subtract node
//--------------------------------------------------------------------------
class SubtractNode : public Node
{
public:
    SubtractNode (Expression *expr);
    ~SubtractNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// Multiply node
//--------------------------------------------------------------------------
class MultiplyNode : public Node
{
public:
    MultiplyNode (Expression *expr);
    ~MultiplyNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// Divide node
//--------------------------------------------------------------------------
class DivideNode : public Node
{
public:
    DivideNode (Expression *expr);
    ~DivideNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// GT(>) node
//--------------------------------------------------------------------------
class GTNode : public Node
{
public:
    GTNode (Expression *expr);
    ~GTNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// GE(>=) node
//--------------------------------------------------------------------------
class GENode : public Node
{
public:
    GENode (Expression *expr);
    ~GENode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// LT(<) node
//--------------------------------------------------------------------------
class LTNode : public Node
{
public:
    LTNode (Expression *expr);
    ~LTNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// LE(<=) node
//--------------------------------------------------------------------------
class LENode : public Node
{
public:
    LENode (Expression *expr);
    ~LENode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// EQ(==) node
//--------------------------------------------------------------------------
class EQNode : public Node
{
public:
    EQNode (Expression *expr);
    ~EQNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// NE(!=) node
//--------------------------------------------------------------------------
class NENode : public Node
{
public:
    NENode (Expression *expr);
    ~NENode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// And (&&) node
//--------------------------------------------------------------------------
class AndNode : public Node
{
public:
    AndNode (Expression *expr);
    ~AndNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// Or(||) node
//--------------------------------------------------------------------------
class OrNode : public Node
{
public:
    OrNode (Expression *expr);
    ~OrNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// Not (!) node
//--------------------------------------------------------------------------
class NotNode : public Node
{
public:
    NotNode (Expression *expr);
    ~NotNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_rhs;
};

// Negate node
//--------------------------------------------------------------------------
class NegateNode : public Node
{
public:
    NegateNode (Expression *expr);
    ~NegateNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_rhs;
};

// Exponent node
//--------------------------------------------------------------------------
class ExponentNode : public Node
{
public:
    ExponentNode (Expression *expr);
    ~ExponentNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    Node *m_lhs;
    Node *m_rhs;
};

// Variable node (also used for constants)
//--------------------------------------------------------------------------
class VariableNode : public Node
{
public:
    VariableNode (Expression *expr);
    ~VariableNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    double *m_var;
    std::string var_ident;
};

// Value node
//--------------------------------------------------------------------------
class ValueNode : public Node
{
public:
    ValueNode (Expression *expr);
    ~ValueNode();

    double DoEvaluate (ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const;
    std::pair<double, double> DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const;
    void Parse (
        Parser &parser,
        Parser::size_type start,
        Parser::size_type end,
        Parser::size_type v1,
        bool &good_parse);

    std::string
    get_renamed_expression (
        const std::string& var_map_name) const;

private:
    double m_val;
};

} // namespace ExprEval

#endif // __EXPREVAL_NODE_H
